﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using SdmxMl.Helper;
using SdmxMl.Common;

namespace SdmxMl.Structure
{
    /// <summary>
    /// Representation schemes indicated which values are valid for identifying objects
    /// within each class. For any given representation scheme, two IDs must be provided:
    /// the RepresentationScheme must have an ID as assigned to it by it representationSchemeAgency,
    /// whose ID must also be provided. The type of the representation scheme is expressed in the
    /// representationSchemeType attribute.
    /// </summary>
    public class RepresentationSchemeType : ArtefactRefBase

    {
        #region Properties

        // SDMX 2.0
        private RepresentationSchemeTypeType _representationSchemeType;

        // SDMX 2.1
        private ItemSchemeTypeCodelistType _class;
        private ItemSchemePackageTypeCodelistType _package;

        public RepresentationSchemeTypeType SchemeType //{ get; set; }
        {
            get { return _representationSchemeType; }
            set { _representationSchemeType = value; }
        }

        #endregion // Properties

        #region Constructors

        public RepresentationSchemeType()
        {
            Init();
        }

        public RepresentationSchemeType(string id, string agency, string vers) : base( id, agency, vers)
        {
            Init();
        }

        private void Init()
        {
            _representationSchemeType = RepresentationSchemeTypeType.External;
        }


        public RepresentationSchemeType(XmlNode nodeArtefact, SdmxNamespaceManager nsmgr)
        {
            Init();

            if (nsmgr.VersionSdmx == SdmxVersion.SDMX_20)
            {

                Id = Xmlhelper.GetAtt(nodeArtefact, "representationScheme");
                AgencyId = Xmlhelper.GetAtt(nodeArtefact, "representationSchemeAgency");
                Version = Xmlhelper.GetAtt(nodeArtefact, "representationSchemeVersion");

                string str = Xmlhelper.GetAtt(nodeArtefact, "representationSchemeType");
                if (Enum.IsDefined(typeof(RepresentationSchemeTypeType), str))
                    _representationSchemeType = (RepresentationSchemeTypeType)Enum.Parse(typeof(RepresentationSchemeTypeType), str, true);
                else
                    throw new ApplicationException("Unrecognised RepresentationSchemeTypeType: " + str);
            }
            else
            {
                
                //Enumeration exists ?
                XmlNode ndEnum = nodeArtefact.SelectSingleNode("./structure:Enumeration", nsmgr);
                if (ndEnum != null)
                {
                    XmlNode ndRef = ndEnum.SelectSingleNode("./Ref", nsmgr);
                    if (ndRef != null)
                    {
                        Id = Xmlhelper.GetAtt(ndRef, "id");
                        AgencyId = Xmlhelper.GetAtt(ndRef, "agencyID");
                        Version = Xmlhelper.GetAtt(ndRef, "version");
                        string cp = Xmlhelper.GetAtt(ndRef, "class");
                        if (Enum.IsDefined(typeof(ItemSchemeTypeCodelistType), cp))
                            _class = (ItemSchemeTypeCodelistType)Enum.Parse(typeof(ItemSchemeTypeCodelistType), cp, true);
                        cp = Xmlhelper.GetAtt(ndRef, "package");

                        // base is reserved in c#
                        if (cp == "base")
                            cp = "Base";

                        if (Enum.IsDefined(typeof(ItemSchemePackageTypeCodelistType), cp))
                            _package = (ItemSchemePackageTypeCodelistType)Enum.Parse(typeof(ItemSchemePackageTypeCodelistType), cp, true);

                        //set _representationSchemeType
                        _representationSchemeType = RepresentationSchemeType21Helper.GetRepresentationFor20(_package);
                    }
                    else
                    {
                        //TODO URN
                    }
                }

            }
        }
        
        public RepresentationSchemeType Clone()
        {
            RepresentationSchemeType copy = new RepresentationSchemeType(Id, AgencyId, Version);
            copy.SchemeType = SchemeType;
            return copy;
        }
        
        #endregion //Constructors

        public void WriteXml(XmlTextWriter xw, string prefix, string tag)
        {
            if (SdmxNamespaceManager.SdmxTarget == SdmxVersion.SDMX_20)
            {

                if (string.IsNullOrEmpty(Id) == false)
                {
                    xw.WriteStartElement(prefix, tag, null);

                    // Required
                    xw.WriteAttributeString("representationScheme", Id);
                    xw.WriteAttributeString("representationSchemeAgency", AgencyId);
                    if (Version != "1.0")
                        xw.WriteAttributeString("representationSchemeVersion", Version);


                    xw.WriteAttributeString("representationSchemeType", _representationSchemeType.ToString());


                    xw.WriteEndElement();
                }
            }
            else // SDMX 21
            {
                xw.WriteStartElement(prefix, tag, null);
                if (string.IsNullOrEmpty(Id) == false)
                {
                    xw.WriteStartElement(prefix, "Enumeration", null);
                    xw.WriteStartElement("Ref");
                    xw.WriteAttributeString("id", Id);
                    xw.WriteAttributeString("package", 
                        RepresentationSchemeType21Helper.GetPackageFor21(_representationSchemeType).ToString().ToLower());
                    xw.WriteAttributeString("class", 
                        RepresentationSchemeType21Helper.GetClassFor21(_representationSchemeType).ToString());
                    xw.WriteAttributeString("agencyID", AgencyId);
                    if (Version != "1.0")
                        xw.WriteAttributeString("version", Version);

                    xw.WriteEndElement();
                    xw.WriteEndElement();
                }
                else
                {
                    xw.WriteElementString(prefix, "TextFormat", null, null);
                }


                xw.WriteEndElement();
            }
        }

        public override string ToString()
        {
            if (string.IsNullOrEmpty(Id) == false &&
                string.IsNullOrEmpty(AgencyId) == false)
                return _representationSchemeType.ToString() + " - " + Version + " - "  + Id + " - " + AgencyId;
            return string.Empty;
        }

        /// <summary>
        /// Helper to translate type to general enumeration of ML
        /// </summary>
        /// <returns></returns>
        public SdmxMl.Manager.SdmxArtefactType DetermineArtefactType()
        {
            SdmxMl.Manager.SdmxArtefactType arType = SdmxMl.Manager.SdmxArtefactType.None;
            switch (SchemeType)
            {
                case RepresentationSchemeTypeType.Codelist:
                    arType = SdmxMl.Manager.SdmxArtefactType.CodeLists;
                    break;

                case RepresentationSchemeTypeType.Concept:
                    arType = SdmxMl.Manager.SdmxArtefactType.Concepts;
                    break;

                case RepresentationSchemeTypeType.Category:
                    arType = SdmxMl.Manager.SdmxArtefactType.CategorySchemes;
                    break;

                case RepresentationSchemeTypeType.Organisation:
                    arType = SdmxMl.Manager.SdmxArtefactType.OrganisationSchemes;
                    break;
            }
            return arType;

        }
    }
}
